/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package mybatis;

import common.BulkInsertTestBase;
import domain.Note;
import mapper.Mapper;
import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.jdbc.ScriptRunner;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.defaults.DefaultSqlSessionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;

import java.io.IOException;
import java.io.Reader;
import java.sql.Connection;
import java.util.List;

/**
 * Performs bulk insert in three different ways.
 * <ul>
 * <li>insertOneToMany</li>
 * </ul>
 *
 * @author Iwao AVE!
 */
//@FixMethodOrder(MethodSorters.DEFAULT)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
//@FixMethodOrder(MethodSorters.JVM)
public abstract class MybatisBulkInsertTestBase extends BulkInsertTestBase {

    protected static SqlSessionFactory sqlSessionFactory;
    protected SqlSession sqlSession;
    protected Mapper mapper;

    public static void buildSqlSessionFactory(Class<?> mapperClass) throws Exception {
        UnpooledDataSourceFactory dataSourceFactory = new UnpooledDataSourceFactory();
        dataSourceFactory.setProperties(datasourceProperties);

        Environment environment = new Environment("test", new JdbcTransactionFactory(), dataSourceFactory.getDataSource());
        Configuration configuration = new Configuration();
        configuration.setEnvironment(environment);
//        configuration.setLogImpl(StdOutImpl.class); // unblock this line to shwo sql
        if (isOracle()) {
            // In XML mappers, statements with databaseId="oracle" will be used.
            configuration.setDatabaseId("oracle");
        }
        configuration.addMapper(mapperClass);
        sqlSessionFactory = new DefaultSqlSessionFactory(configuration);
    }

    public void openSession() {
        sqlSession = sqlSessionFactory.openSession();
        mapper = (Mapper) sqlSession.getMapper(mapperClass());
    }

    //    @Before
//    public void initDb() throws IOException {
    public static void initDb() throws IOException {
        SqlSession session = sqlSessionFactory.openSession();
        Connection conn = session.getConnection();
        Reader reader = Resources.getResourceAsReader("create.sql");
        ScriptRunner runner = new ScriptRunner(conn);
        runner.setLogWriter(null);
        runner.runScript(reader);
        reader.close();
        session.close();
    }

    @Test
    public void test01InsertOneToManyAndQeury() throws Exception {
        try {
            openSession();
            // transactional in service method begin
            mapper.insertPerson(person);
            mapper.insertNotes(person.getNotes());
            // transactional in service method end
            sqlSession.commit();

            jsonPrettyPrinter(mapper.queryPerson(person));
        } finally {
            sqlSession.close();
        }
    }

    @Test
    public void test02UpdateOneToManyAndQeury() throws Exception {
        try {

            // update date
            person.setName("hello newer :)");
            for (int i = 0; i < person.getNotes().size(); i++) {
                if (i % 2 == 0) {
                    person.getNotes().get(i).setContext("new note " + (i + 1));
                }
            }

            openSession();
            // transactional in service method begin
            mapper.updatePerson(person);
            mapper.updateNotes(person.getNotes());
            // transactional in service method end
            sqlSession.commit();

            jsonPrettyPrinter(mapper.queryPerson(person));
        } finally {
            sqlSession.close();
        }
    }

    @Test
    public void test03DeleteOneToManyAndQeury() throws Exception {
        try {
            openSession();
            // transactional in service method begin
            mapper.deleteNotesByPersonId(person.getId());
            mapper.deletePersonById(person.getId());
            // transactional in service method end
            sqlSession.commit();

            jsonPrettyPrinter(mapper.queryPerson(person));
        } finally {
            sqlSession.close();
        }
    }

    protected abstract Class<?> mapperClass();
}